#ifndef NesCPU6502_H_INCLUDED
#define NesCPU6502_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif

#include "stdint.h"


/* 中断地址 */
#define NMIVector   0xFFFA
#define ResetVector 0xFFFC
#define IRQVector   0xFFFE


#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif


typedef enum
{
    vCPU_None = 0,
    vCPU_Acc,  vCPU_Imp,   vCPU_Imm,   vCPU_Rel,
    vCPU_Zero, vCPU_Abs,   vCPU_ZeroX, vCPU_ZeroY,
    vCPU_Ind,  vCPU_IndX,  vCPU_IndY,  vCPU_IndYW,
    vCPU_AbsX, vCPU_AbsXW, vCPU_AbsY,  vCPU_AbsYW
}ModeEnum;

typedef enum{
    Carry     = 0x01,
    Zero      = 0x02,
    Interrupt = 0x04,
    Decimal   = 0x08,
    Break     = 0x10,
    Reserved  = 0x20,
    Overflow  = 0x40,
    Negative  = 0x80
}CPUStateEnum;

typedef struct{
    uint8_t A;
    uint8_t Y;
    uint8_t X;
    uint8_t PS;
    uint16_t PC;
    uint8_t SP;
}CPURegisterType;

/*
  0000h-07FFh   Internal 2K Work RAM (mirrored to 800h-1FFFh)
  2000h-2007h   Internal PPU Registers (mirrored to 2008h-3FFFh)
  4000h-4017h   Internal APU Registers
  4018h-5FFFh   Cartridge Expansion Area almost 8K
  6000h-7FFFh   Cartridge SRAM Area 8K
  8000h-FFFFh   Cartridge PRG-ROM Area 32K
*/
typedef struct{
    /* 2kByte */
    uint8_t *RAM;
    /* 8kByte */
    uint8_t *SRAM;
    /* CPU代码区第0个 8kBtye */
    uint8_t *ROMBank0;
    /* CPU代码区第1个 8kByte */
    uint8_t *ROMBank1;
    /* CPU代码区第2个 8kBtye */
    uint8_t *ROMBank2;
    /* CPU代码区第3个 8kByte */
    uint8_t *ROMBank3;

    CPURegisterType registers;

    void (*Function)(void);
    ModeEnum Mode;
    uint32_t operand;
    uint32_t opCode;

    uint32_t IRQFlag : 1;
    uint32_t NMIFlag : 1;
    uint32_t ResetFlag : 1;

    /* PPU已运行时钟数 */
    uint64_t clockCnt;
}NesCPUInofType;



uint32_t cNesCPUBankAddr8kByteSet(uint32_t cSerial, uint32_t uiAddr);
uint32_t cNesCPUBankAddr16kByteSet(uint32_t cSerial, uint32_t uiAddr);
uint32_t cNesCPUBankAddr32kByteSet(uint32_t uiAddr);

void vNesCPUMemoryLoad(uint32_t addr, uint32_t uiAddr, uint32_t iLength);

void vNesCPUStart(void);
void vNesCPUInit(void);
void vNesCPUExec(void);

NesCPUInofType *ptyeNesCPUInfoGet(void);


#ifdef __cplusplus
}
#endif

#endif // NesCPU6502_H_INCLUDED
